#include <iostream>
#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>
using namespace std;

bool kbhit()
{
    termios term;
    tcgetattr(0, &term);

    termios term2 = term;
    term2.c_lflag &= ~ICANON;
    tcsetattr(0, TCSANOW, &term2);

    int byteswaiting;
    ioctl(0, FIONREAD, &byteswaiting);

    tcsetattr(0, TCSANOW, &term);

    return byteswaiting > 0;
}

void echo_on()
{
    static bool init = false;
    static struct termios init_setting;
    if (!init)
    {
        tcgetattr(0, &init_setting);
        init = true;
    }

    struct termios new_setting = init_setting;
    
    new_setting.c_lflag |= ECHO;
    tcsetattr(0, TCSANOW, &new_setting);
}

void echo_off()
{
    static bool init = false;
    static struct termios init_setting;
    if (!init)
    {
        tcgetattr(0, &init_setting);
        init = true;
    }

    struct termios new_setting = init_setting;

    new_setting.c_lflag &= ~ECHO;
    tcsetattr(0, TCSANOW, &new_setting);
}

#if 0
static bool kbhit(void)
{
    struct timeval tv;
    fd_set rdfs;

    tv.tv_sec = 0;
    tv.tv_usec = 0;

    FD_ZERO(&rdfs);
    FD_SET(STDIN_FILENO, &rdfs);

    select(STDIN_FILENO + 1, &rdfs, NULL, NULL, &tv);
    return FD_ISSET(STDIN_FILENO, &rdfs);
}
#endif

int main()
{
    int c;

    echo_on();
    cout << "Echo on" << endl;
    for (int i = 0; i < 5; ++i)
    {
        c = fgetc(stdin);
    }

    echo_off();
    cout << "Echo off" << endl;
    for (int i = 0; i < 5; ++i)
    {
        c = fgetc(stdin);
        cout << "Manual Echo: " << c << endl;
    }

    echo_on();

    int i;
    while (true)
    {
        i++;
        if (i == 1000000)
        {
            i = 0;
            echo_off();
            cout << "Echo off" << endl;
        }
        if (kbhit())
        {
            c = fgetc(stdin);

            switch (c)
            {
            case 'h':
                cout << "you input h"<<endl;
                break;
            case 'p':
                cout << "you input p"<<endl;
                break;
            default:
                break;
            }
        }
    }
    return 0;
}
